import axios from 'axios'
import { ElMessage, ElLoading } from 'element-plus'
import Cookies from 'js-cookie'
import router from '@/router'
import store from '@/store'
import i18n from '@/i18n'
import { INVALID_LOGIN_CODE, SUCCESS_CODE, INVALID_LOGIN_URL, JS_CONTEXT } from '@/constants'
const service = axios.create({
  // baseURL: JS_CONTEXT.BASE_URL
})

// 请求拦截器
service.interceptors.request.use(config => {
  config.headers['Content-Type'] = 'application/json'
  return config
})

// 响应拦截器
axios.interceptors.response.use(async res => {
  const r = res.data
  const returnResult = {
    ...res,
    data: r
  }
  return r.code === INVALID_LOGIN_CODE ? { invalidLogin: true, message: returnResult.message } : returnResult
})

export function myAjax ({
  url,
  data = {},
  loadingDom, // 加载loading的元素， 可以是class、id等
  loadingObject, // 参考element-ui, https://element.eleme.cn/#/zh-CN/component/loading
  method = 'post',
  invalidLoginUrl = '/login',
  showErrorMessageBox = true, // 是否非SUCCESS_CODE状态时直接报错
  errorMessageBoxUseHtml = false, // 这个提示是否用html格式
  timeout = 0,
  // responseType 默认是json
  // axios允许值 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType = 'json',
  headers = {},
  isFormData = false, // 是不是formData，该方法只适用于post
  withCredentials = false, // 表示跨域请求时是否需要使用凭证
  onUploadProgress = null, // 上传进度函数
  onDownloadProgress = null, // 下载进度函数
  cancelToken = null // 取消ajax请求，
  // 取消请参考 http://www.axios-js.com/zh-cn/docs/#%E5%8F%96%E6%B6%88
}) {
  url = window.config.BASE_URL + url
  // 设置loading
  const loadingInstant = setLoading(loadingDom, loadingObject)
  // 设置请求头
  const defaultHeaders = {
    token: Cookies.get('token'),
    'Content-Type': 'application/json',
    ...headers
  }
  // 请求axios配置项
  const axiosOption = {
    url: url,
    method: method,
    timeout: timeout,
    responseType: responseType,
    withCredentials: withCredentials,
    headers: defaultHeaders,
    cancelToken: cancelToken,
    ...setAxiosParams(method, data, isFormData)
  }
  if (onDownloadProgress) axiosOption.onDownloadProgress = onDownloadProgress
  if (onUploadProgress) axiosOption.onUploadProgress = onUploadProgress
  return service(axiosOption).then(res => {
    // blob是需要获取文件名的，一般的文件名放到了响应头中
    if (res) {
      // 如果登录失效后
      if (res?.data?.statusCode === INVALID_LOGIN_CODE) {
        ElMessage({
          message: i18n.global.t('msg.login.loginInvalid'),
          type: 'error',
          duration: 5000
        })
        store.dispatch('user/loginOut')
        router.push({ path: INVALID_LOGIN_URL })
        return res
      }
      // 全局统一接口错误提示
      if (responseType !== 'blob' && res.data && res.data.statusCode !== SUCCESS_CODE && showErrorMessageBox) {
        ElMessage({
          message: res.data.message,
          dangerouslyUseHTMLString: errorMessageBoxUseHtml,
          type: 'error',
          duration: 5000
        })
      }
      return responseType === 'blob' ? { data: res.data, headers: res.headers } : res.data
    }
  }).catch(function (err) {
    const response = err.response || { data: {} }
    const msg = response.data.msg || response.data.message || i18n.global.t('msg.common.requestError')
    ElMessage({
      message: msg,
      type: 'error',
      duration: 5000
    })
    return Promise.reject(err)
  }).finally(() => {
    if (loadingInstant) {
      loadingInstant.close()
    }
  })
}

// 配置指令loading
const setLoading = (loadingDom, loadingObject) => {
  let loadingInstant
  if (loadingDom) {
    // 默认loading配置项
    const loadingOptionsDefault = {
      lock: true,
      text: 'Loading',
      background: 'rgba(0, 0, 0, 0.7)'
    }
    let loadingOptions = {}
    if (loadingObject && typeof loadingObject === 'object') {
      loadingOptions = {
        ...loadingOptionsDefault,
        ...loadingObject
      }
    }
    // 服务方式的配置项
    const options = {
      target: loadingDom,
      lock: true,
      ...loadingOptions
    }
    loadingInstant = ElLoading.service(options)
  }
  return loadingInstant
}

/**
 * 设置ajax请求的参数处理
 * @param method 请求方法
 * @param data 请求参数
 * @param isFormData 是不是FormData数据
 * **/
const setAxiosParams = (method, data, isFormData) => {
  const option = {}
  if (method === 'get') {
    option.params = data
  } else if (method === 'post' && !isFormData) {
    // 这里的数据默认是对象，对象是需要进行序列化的，请根据后台实际情况修改
    option.data = data
    option.transformRequest = [function (d) {
      return JSON.stringify(d)
    }]
  } else if (isFormData) {
    // 这里默认你传的是普通的 plain object
    // 此处对plain object进行formData化
    const formData = new FormData()
    for (const k in data) {
      formData.append(k, data[k])
    }
    option.data = formData
  }
  return option
}
